package cartagows.wsframework.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;

import cartago.Artifact;
import cartago.GUARD;
import cartago.OPERATION;
import cartago.OpFeedbackParam;

/**
 * Class that represent a generic RequestMediatorArtifact able to coordinate
 * the request between the framework Workers and the services requestors 
 * @author Andrea Santi
 *
 */
public class RequestMediator extends Artifact{

	private HashMap<String, IRequest> requests;
	private ArrayList<String> requestsUnderProcessing;

	@OPERATION void init(){
		requests = new HashMap<String, IRequest>();
		requestsUnderProcessing = new ArrayList<String>();
	}

	/**
	 * Operation used to store a new request in the artifact 
	 * @param req
	 */
	@OPERATION public void addNewRequest(IRequest req, OpFeedbackParam<String> requestIDFeedback){
		String requestID = UUID.randomUUID().toString();
		req.setRequestID(requestID);
		requests.put(requestID, req);
		requestIDFeedback.set(requestID);
	}

	/**
	 * Operation used for retrieve a new request stored in the artifact
	 */
	@OPERATION(guard="checkRequestAvailability") public void getNextRequest(OpFeedbackParam<IRequest> res){
		IRequest returnValue = null;
		for (IRequest reqInfo : requests.values()){
			if(!requestsUnderProcessing.contains(reqInfo.getRequestID())){
				returnValue = reqInfo;
				requestsUnderProcessing.add(reqInfo.getRequestID());
				break;
			}
		}
		res.set(returnValue);
	} 

	/**
	 * Operation used for notify to the mediator the completion of the request identified
	 * by the requestID given in input
	 * @param requestID
	 * @param result
	 */
	@OPERATION(guard="checkRequestPresence") public void notifyRequestCompletion(String requestID, DataContainer result, boolean isRequestSucceeded){
		requests.get(requestID).notifyRequestCompletion(result, isRequestSucceeded);
	}

	/**
	 * Operation used for the retrieval of the result of the request identified
	 * by the requestID given in input . After the retrieval of the request result
	 * the request is considered successfully processed (independently from the result obtained)
	 * @param requestID
	 */
	@OPERATION(guard="checkRequestCompletion") public void getRequestResult(String requestID, OpFeedbackParam<IRequest> res){
		IRequest request = requests.get(requestID);
		requests.remove(requestID);
		requestsUnderProcessing.remove(requestID);
		res.set(request);
	}

	/**
	 * Guard that checks the availability of at least one request
	 * @return
	 */
	@GUARD public boolean checkRequestAvailability(OpFeedbackParam<IRequest> res){
		return ((requests.size() != 0) && (requests.size()!=requestsUnderProcessing.size()));
	}
	/**
	 * Guard that checks that the request identified by the requestID given in
	 * input exist and under processing
	 * @param requestID
	 * @param result
	 * @param isRequestSucceeded
	 * @return
	 */
	@GUARD public boolean checkRequestPresence(String requestID, DataContainer result, boolean isRequestSucceeded){
		return (requests.containsKey(requestID) && requestsUnderProcessing.contains(requestID));
	}

	/**
	 * Guard that checks the completion of the request identified by the requestID
	 * given in input
	 * @param requestID
	 * @return
	 */
	@GUARD public boolean checkRequestCompletion(String requestID, OpFeedbackParam<IRequest> res){
		return (requests.containsKey(requestID) && (requestsUnderProcessing.contains(requestID)) && requests.get(requestID).isRequestCompleted());
	}
}
